package cn.wolfcode.shiro;

import cn.wolfcode.domain.Employee;
import cn.wolfcode.service.IEmployeeService;
import cn.wolfcode.service.IPermissionService;
import cn.wolfcode.service.IRoleService;
import cn.wolfcode.util.UserContext;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

@Component
public class CrmRealm extends AuthorizingRealm {
    //....

    @Autowired
    private IEmployeeService employeeService;

    @Autowired
    private IPermissionService permissionService;

    @Autowired
    private IRoleService roleService;

    /**
     * 提供授权信息
     *
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        System.out.println("doGetAuthorizationInfo--------");
        // 1. 获取当前登录的员工的对象, 获取员工id
        //Employee currentUser = UserContext.getCurrentUser();
        Employee currentUser = UserContext.getCurrentUser();
        //System.out.println(currentUser);
        //Employee employee  = (Employee) principals.getPrimaryPrincipal();
        // 2. 查询数据库该员工的拥有的角色和权限数据
        // 3. 设置当前登录用户的角色和权限数据, 不是数据库的全部权限和角色, 是用户自身拥有的
        // 分配角色
        if (currentUser.isAdmin() == false) {
            // 权限表达式
            List<String> expressions = permissionService.selectByExpressionByEmpId(currentUser.getId());
            //info.addRoles(Arrays.asList("hr", "seller"));
            //info.addStringPermissions(Arrays.asList("employee:save", "employee:delete"));
            // 给shiro提供权限表达式
            info.addStringPermissions(expressions);
            System.out.println(expressions);
            // 获取角色
            List<String> sns = roleService.selectSnByEmpId(currentUser.getId());
            System.out.println(sns);
            // 给shiro提供角色
            info.addRoles(sns);

        } else {
            // 权限拦截的功能是shiro来做的, 不知道Employee的属性的意义, 它依然是按照权限表达式去判断, 可以给通配符
            info.addStringPermission("*");
            // 或者给全部权限
            info.addStringPermissions(Arrays.asList("*:*"));
            // 自动给一个管理员角色
            System.out.println("admin---------ing");
            info.addRole("admin");
            System.out.println("admin---------finish");
        }


        return info;
    }

    /**
     * 提供认证信息
     *
     * @param token
     * @return SimpleAuthenticationInfo
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        // 如果直接返回null, shiro自动抛出账号不存在的异常
        // 如果返回不为null, shiro就会自动从返回的对象(数据源)中获取真实的密码,再去与token去对比, 密码错误再抛出异常

        // 1. 获取令牌中的用户名  --- 等同于表单传进来的
        String username = (String) token.getPrincipal();
        //UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)token;
        //String username = usernamePasswordToken.getUsername();

        // 2. 查询数据库中是否存在该员工(数据库中是否存在该用户)
        //String name = "孙总";
        //String password = "1";
        Employee employee = employeeService.selectByName(username);

        // 3. 如果不存在, 直接返回null   username.equals(name)
        if (employee != null) {
            // 4. 如果直接存在, 返回AuthenticationInfo的实现类SimpleAuthenticationInfo对象
            // 身份信息可以在任意地方获取到, 用来跟subject绑定在一起
            // 在项目中就直接传入员工的对象, 跟subject绑定在一起, 方便我们后续在任意地方获取当前登录的员工对象
            // 传入真实的密码, shiro会自动判断是否正确
            // 传入当前数据源的名字, 但是对于我们现在的项目没有作用, 一般是一个项目中有多个数据源, 需要做标志, 该数据是从哪个数据源查的


            //如果直接抛出shiro提供的异常, 就不会被封装, 如果抛自定义异常, 就会被shiro封装
            if (employee.isStatus() == false) {
                throw new DisabledAccountException("账号被禁用");
            }

            return new SimpleAuthenticationInfo(employee, employee.getPassword(), this.getName());
        }
        return null;
    }
}

